{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#hide\n",
    "!pip install -Uqq fastbook\n",
    "import fastbook\n",
    "fastbook.setup_book()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#hide\n",
    "from fastbook import *"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# A fastai Learner from Scratch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This final chapter (other than the conclusion and the online chapters) is going to look a bit different. It contains far more code and far less prose than the previous chapters. We will introduce new Python keywords and libraries without discussing them. This chapter is meant to be the start of a significant research project for you. You see, we are going to implement many of the key pieces of the fastai and PyTorch APIs from scratch, building on nothing other than the components that we developed in <<chapter_foundations>>! The key goal here is to end up with your own `Learner` class, and some callbacks—enough to be able to train a model on Imagenette, including examples of each of the key techniques we've studied. On the way to building `Learner`, we will create our own version of `Module`, `Parameter`, and parallel `DataLoader` so you have a very good idea of what those PyTorch classes do.\n",
    "\n",
    "The end-of-chapter questionnaire is particularly important for this chapter. This is where we will be pointing you in the many interesting directions that you could take, using this chapter as your starting point. We suggest that you follow along with this chapter on your computer, and do lots of experiments, web searches, and whatever else you need to understand what's going on. You've built up the skills and expertise to do this in the rest of this book, so we think you are going to do great!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's begin by gathering (manually) some data."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Have a look at the source to `untar_data` to see how it works. We'll use it here to access the 160-pixel version of Imagenette for use in this chapter:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "path = untar_data(URLs.IMAGENETTE_160)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To access the image files, we can use `get_image_files`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Path('/home/jhoward/.fastai/data/imagenette2-160/val/n03417042/n03417042_3752.JPEG')"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t = get_image_files(path)\n",
    "t[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Or we could do the same thing using just Python's standard library, with `glob`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Path('/home/jhoward/.fastai/data/imagenette2-160/val/n03417042/n03417042_3752.JPEG')"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from glob import glob\n",
    "files = L(glob(f'{path}/**/*.JPEG', recursive=True)).map(Path)\n",
    "files[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you look at the source for `get_image_files`, you'll see it uses Python's `os.walk`; this is a faster and more flexible function than `glob`, so be sure to try it out.\n",
    "\n",
    "We can open an image with the Python Imaging Library's `Image` class:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=213x160 at 0x7FA45AC27D50>"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "im = Image.open(files[0])\n",
    "im"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([160, 213, 3])"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "im_t = tensor(im)\n",
    "im_t.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "That's going to be the basis of our independent variable. For our dependent variable, we can use `Path.parent` from `pathlib`. First we'll need our vocab:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(#10) ['n03417042','n03445777','n03888257','n03394916','n02979186','n03000684','n03425413','n01440764','n03028079','n02102040']"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lbls = files.map(Self.parent.name()).unique(); lbls"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "...and the reverse mapping, thanks to `L.val2idx`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'n03417042': 0,\n",
       " 'n03445777': 1,\n",
       " 'n03888257': 2,\n",
       " 'n03394916': 3,\n",
       " 'n02979186': 4,\n",
       " 'n03000684': 5,\n",
       " 'n03425413': 6,\n",
       " 'n01440764': 7,\n",
       " 'n03028079': 8,\n",
       " 'n02102040': 9}"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v2i = lbls.val2idx(); v2i"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "That's all the pieces we need to put together our `Dataset`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Dataset"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A `Dataset` in PyTorch can be anything that supports indexing (`__getitem__`) and `len`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Dataset:\n",
    "    def __init__(self, fns): self.fns=fns\n",
    "    def __len__(self): return len(self.fns)\n",
    "    def __getitem__(self, i):\n",
    "        im = Image.open(self.fns[i]).resize((64,64)).convert('RGB')\n",
    "        y = v2i[self.fns[i].parent.name]\n",
    "        return tensor(im).float()/255, tensor(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We need a list of training and validation filenames to pass to `Dataset.__init__`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(9469, 3925)"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_filt = L(o.parent.parent.name=='train' for o in files)\n",
    "train,valid = files[train_filt],files[~train_filt]\n",
    "len(train),len(valid)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can try it out:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(torch.Size([64, 64, 3]), tensor(0))"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_ds,valid_ds = Dataset(train),Dataset(valid)\n",
    "x,y = train_ds[0]\n",
    "x.shape,y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAHsAAACMCAYAAABcUNbeAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nO19eayc13Xf737r7MvbV27iIlGkSGuxZclK5CS2ZDuJjNhN6sQx7NRJ6hRokKBIWycp0hZtDBQBCnRH2zRwkzRI09rZvMixK3mRtVk7xU0kH/keH9++zD7zbf3j/O6d4ZM4VOyoBvrmAOSQ33zzfXc7557zO8tVSZJgQLuDrO93Awb0/44Gk72LaDDZu4gGk72LaDDZu4gGk72LaDDZu4i+r5OtlHqHUuoJpVRLKXVNKfXbSim75/tZpdSjSqlFpVSbn59VSs3c4HmWUuqrSqlEKfXRHd/9ulLqG0qpCr+f2fH9Pl5/oz//bse9H1dKnWWbziilfqZPH48qpepKqXDH9UeUUl9QSi0ppRpKqVNKqV9WSqm/zhj+dej7NtlKqVkAXwFwFsBdAD4F4BcB/Iue20IA/wvAjwE4BOAnARwG8Oc3eOw/AdC4wXc+gD/b8fxemgcwuePP3+J3f9TT7g8C+K8A/iOAEwD+M4DPKqXe9wZ9zAD4YwBfe4P3PQjg2wB+AsAxAL8D4DMAfu0G7fveKUmSt+QPgMcA/BcAvwlgCcAGgN8DkOX3/xLAAgCr5zd/D0Bd33OD5z4CIAFQ3HH93QCuABjm9x+9we8f5Pczb6IPfwDg1I5rTwD4wx3X/ieAx97g9/8Nsig+DiB8E+/7NwC+81bNyVvN2R8GMMQB/mkAH0R35d4P4NEkSeKe+78EIAPgbW/0MKXUCICfBfBckiTbPdfHAfx3AB9LkmT9b6LhfNeHAPynnmsegHvYzl76EoB7d2xBH+O9v/LXeG0RwNp32+ab0Vs92VeSJPmVJEnOJEnyJYg4fC+/m4RwfC8t9XxnSCn1P5RSDQCrAKYAPNzznQXhwN9NkuSxv8G2fxxADFlEmkYAODdotw9Z2FBK3QYRy387SZLmm3mZUupBAB8B8G+/l0b3o7d6sl/Y8f+rAMb73J/s+NT0KxBu1/viH/Vw0acBpAD80++hndcRlaRfAPDHSZJs/jV+miilfIhY/40kSV55k++7F8DnAfxWkiQ30ke+d3qr9+wd134DwBz//TiEG3u/PwCZ6Hf1ee4k73m45z0RRJnTfxJeO/Pd7NkAfpj33LvjugcggGwXvdd/DkALgA1gH3/b256o59qn36A91Z3X34o/zt/Mkvmu6FsAflYpZfXs2w9DtOnn+/xOSyOfn58AkN1xz8sAfh2iyX839IsAXkqS5Mnei0mSdJRSzwB4CMBne756GMCTSZJESqmrAI7veN4jEMlzEsCyvqiU+gBECvxmkiS/81229c3T95GzZwFUIGbM7QB+HMA6gM/03P8hAB+DmCZ7AfwIZJHMA8j3effrtHEAeyCD/Ul+/17+f2jHfWMAOgB+6QbP/iCEQ38ZwBEAv8r/v69Pez6OHdo4xKzrAPhnACZ6/oy+ZXPy/Zps/v9eiCnTgig5vw3A7vn+RwE8CWCL91wA8B8AzN7k3W802b/H6zv/fHzHff8IQA1A4SaTd46TdXbnu97kZD92g/bM9XvW9/JH8cUD2gU0wMZ3EQ0mexfRYLJ3EQ0mexfRYLJ3EfUFVVKTo2LHpMfgFicAANmcfNdpbAAA3PQwKtvik3DtAgDA3n8UrdFhAICnBPtwkzSipAIAsDxPXp4pshEKCZddYnXk3dubiGy56I4fkN8BcFtb8puUvMvx+dmpYOn8aQDAxB65P1soIe5UAQDp4ggAoL22gKBRBwAMT+4HAKgtgbrPPfY52FXxQ/gpaRsyaZQyGbnPTcm1chkAMD48gUxe/p2ypJ/loWFsBgKH11YFad2sNrCnZHHcpD3raysAgCunn8TRh/8+AKB6+Kfk3ck8MlV5Z8WVZ1mdBtrXTgEAXv2GIKrzZwV7+sAjH8LKhnh2H/vDf31Df/iAs3cR9eVsNyUopMrmEDvid2h12gAEMgKAyG4jOyar0IZwbJRLoPyY1/iiJIYiKqo8se0d1+J3FmDJgkxsuce1begl6lhyn63kOgA45Hr+F77roDRUNv/Wz0gc+bdny2fiOIAlP/L4nUpJ+4vD40jlRXTlCiIJ3FIJDn0ue2b3yrtH5D1JK0Q7kPaW0iJhvv30U1isCEdHNRmrfKGAw6MibQKOwVB5CACw6PiobgqX5zkuKvLhp2Qssxx31y3Cn5Y+7/mA/PbFMXnm4pqDk3f9KG5GfSfby+UBAHEqhciRF7WDSAaD33WsDoJIRK/jSGMtVYFlcaEgx09AEb9RHGzFSVSx0nNtqFWtwsvKM1xG6jhKwVEU7ZxlS3+HBLm0iFKfA5RyLESR3O/pVWHZSPgyn5OduPK7qf2HMTss4ltPdttNw7ddAMC1hXkAwKXnRZx2tqsol0oAgHuOnwQArG9uImBfUmlpfyblYXxY7ktaspWtbYo4L5fHUVm6Iu/nNhe5GfgWtzqOkRUoZFISSZUbGZPfjsk2FAZruDz3MkfuR3AjGojxXUR9ObvREOXA9gLky7LSbYuKw+pVAEDYrsC1hNsjtAAAXrGIdGFU7nco4pMESUKOTnx+2nxmDJscalF4N2p1eFTkPKuHs7nSXX46tnznxt2tIE3O9pRCTI5OaUlg21DkaF8/Iy1tnDx0O7ZWRVm7dEG4uB53uXZxWZTSelskWSaVRRJQVKelrb5jo0POtmN5Zy7j48H73w4AOHdKuP3Rx58CAIyP78G5OeFsr74IAIhLh6Es2SjTHA+lQiSJjHPsyXPLJYnxCNZW8b+/xhiL3/oUbkQDzt5F1JezHXKIQoA4Ei5PItl4XUf2sXSUR9imSRXLyutsbsMabvMZAQAg5SRIuGlHXKE2OdFWCs4Ozk45Dlx+72kFDcr8eydne3HXfPP46TsWwlA/g893bKPVZbRpRx2i02xifklMLyctukY5n0LOld/mfOlzJaD+0mxjfFjMsff84DsAAE898yQurIuC5lFy5TM+sr4M9UhRnht0ZFyGciX4oZiMqIg08YdOIFDbpl8AEFshLN3XrMuxpY4Uu1BbNw9NGHD2LqK+yyFsi6GuXAvNhqwmn/uo1oaRKiCOZZUGbeHmVivAaIaathJOScIOXF++tyH3gxq7bXmmIbbqcq7mYo+cZ8Eye7aj9/EeDtfXXHKs59iw2E6tjduOA8tP8RqlSCKfLddFOkfOU9LfoFHF/ScPAQBW5y8BAC5ekz3Wt3yMU3sfzcu+PzFcRMA9tZAWE2l0KANeQiGTNn2R8cygnJZ/V1fm5BkHHYSUdHZHj6NvrJgkjPkM2ddfPfUKllfmcTPqz/tUrsJmCy5ENCkqM86YdAQJENRk8OKUKC7+5ChiRQUtqAEAGuESfCWvS8k4wlNjbLQHZWsxnmLnbFgOO+zKc11E8NhRT8lC8TlonuoqaDZtdduxjbjPQraOwPXh0fr3OaBF2uUnb7kFLz8vqNRmS55RcDuYGhMbemJY3jkzJYrR1MwMbpkUpNB1pVM538cwzb3hnDBG3gPWFmUyFhdECXNc+W6z3UE6L8pvsHBW+m5vIxPSdNUWY6KM6RoSz7hw8QwA4Et/9Xl4Q9K/fjQQ47uI+oMqeeHeqFNBVBUQIEnkJ7WmKGXFbAo2laBUXla3PVyCa4t4S6pirpRSCSxKbwSCTbtZiiPbASxyI8WnYyu4XMEpinsXLXi2PMShaaI5xAEQ1AlU5AXASMdAQs7OkC0algNLK3JkmzSRvCPTIyhpqUMF9MSth5BLi7QpZ+TaZFn6dmBmFBlKjEtnXpK2Jk2UqNjmIEptWuXwygvPAQC2tuVaIS/SYqVSw8joFABgde48ACAOVpF3DgIAWhCppiIFW8kYdbjt6I5MjM9iM67gZjTg7F1EfTnbAnHqXA4O97VOWzgqqMkKrbc7SHuidGhzwm+2kCnJXt2KhLOd9VWojnBh4FPJmyIbOR58Km0WzbLA6iBPrsmG5F47AzsRJc+1ZCXHNpW8OEKD3rfU8DQAoJgoNDW27GjY1EJEc0b3SSP9Wc/FREHaFEXy7smcj2sXRTFLKDnysbQhXltALRAg6dTGHADgvjtvR4HetOGcgEcd20c5kfG4dk1w8Meek2euv/wqMkYppKK4uoTirHC2FVNBQ2L2bC2Zokja7XoOmq0Wbkb9FbRYHlZrBihQXAZ037kRHRdhiHZLJirqyAvba6sojqyyZTIBnfoW1q7J98O3SEd82q12HCPLd2UoPksjeRzeL//uZGSQN7d8lKjN7j8oLteI77bjHK6y2ZZWfT0Fty0jpO3syFKIOKg+nSMqkXdfOncWOVvub3e41URtnHpRRPTRAzKJ97xTMOp8zjHOmvEhEe3PvngKjz/5HQDA4uXXAADNTge/9glJCPW4+IbLIsbL2TRaROTyQ6Ls1ebPYebAOzjeeopiKL5NT3JMxhgeGcOVSztD519PAzG+i6gvZ9MaQq5UQqsiK92mDBnJyUqubK4j7NDBTo6qX1vCmiPcMH1IzCs/twelCVnNQ3tuAQDElEtDTogZeohG6PqbOj6B2uo3AADtnIjAI3v24vYD4mbMpEREvvrVrwMAZg/sw9fZ3oi7Q+QBXoeczfSxABEScrLL98fcfhr1Jh56WNLJXjsvytKdd9+NvZOiQL36oqSuffmr/wcAsLBwAV5GRPCn/+E/AAA88dI5PHtuAQBQ2xTpNjuSNzh/ZXPLjBsATI0O4/zliwCALIMiGosXASXjbdmibFrKgk6Bs6ioLV4Vc64dBoh8nSBzYxpw9i6ivpydcB/Nl0rYbMrqdwlwVNdE8WrXa7AUse5EVrmngGhJVt1WIihcemwUY9P75BmQ1TpGxeRAxoe1LvuytSHvPHnPOzB6TKSCKu8BAFytRyinhW2vXhbv1EhBOObi2VOwuZdluYYzcQJtpWh0DXGEqC26g8M9L8tAgTtOHMPvf+4LAICzl6T9jz/7Cv75P/5VAMB3XhXQ42tPi9RK5zzszWgwSLhu7769WO7IsK4SpC/kXMzPC+qW8YQDk1DGc2Z8HJeXr0l7UuS91TU0W4I8ehn6wSMLiIWjfQI4J04cAwB87vmvojB8BDej/nBpIBMbdTpIpUUxamxSu07kOyQRqOdA0RGigtjYte1FEVd2ZhhJLB11Qro4txhPBhejWUHmjp08AQA4OD2FDGO+Njvy3FZ1AZmciPmYyNye26j5Nmfw4oXLAIB0RwYlGwIN42ARcpVCmxOj4VKX+lw7CHD5mojetZr0b+/UEOjPwOSMKGZ7bhFLwPFtTJSo7dNKcOI2HMLHYyXZtgpZF0o7Yrjm8oRX4zhALiuBINuM6zt58jgUt8TImNQKCXEBl+1ucSUfu/PdOHLHO3AzGojxXUR9OTtuiuLVWV5FQts4PSSiN023X9hoolXTNWuEo5IoRJtuwIjhNZPpGUwxAOL2I+JYuGNalLyjM6MYHxYsXZtDSPTTgOUaIz5ViDRRNf3ODZoj48PD+NAjUtTh/LxIk81GDIe2ukafLAXoekQJv4MiKpf2MD4t7WjT7s+mgDgSrs2mhbOKGbK6HSO2pL0hHTjbm1WEbXlumqG4hXLKmJlBS8Y0R87erjcwwdi5zS3h7Onbb0eYEm5fohRSFkU5AHYFRUbdvm38AMLrajG9MQ04exdRf1CFLJDEMeKO7GEdgg05ggi5qRlsrwlw0uAe7MYBSmUBPX7wfR+Wz3e/G8cO7gMAjApzIiYIMzYy0X2nTipVMGBNo0aAw3HN6swQXGk0hMPXVYyLF0SBOvE22b+W1rZw8YLsry5RMkvFSCgNYnq/Qq3FKRtBQKWU2HXUbiNuM+jPE25zhqVSiJV1UGQ7OtRHRqf3YF9G+qW4j8dbq3AY9BGRK7WXLJ3JwHfkGfPXRClMO0AzFgngM0AhTpRRNnXpgjjp/t+2egbuBjTg7F1EfTk7zUwI33ER0KzRoTFRQhdWJosDx2TvmD8r4EBOhfj5n/sEAOCnPyrF/9KOArEOtNYE2NSARJIkUGRpvWqVUghCrfHLh2/bJrhhaFigxemMaOxzF89jjl6jalV873ff83bM3ivBgt984hl5d6NjAgcMp3T/ge0NkU5VZo3kPRuhNtH4rvGS7LHZcgZ5E1wo95QyPoYDGZtOUzh7eXMTvhKrIbL5LOLmCAI0N0X6TDGLJu/bsJkZU+VnG54ZG+P00pxtAd08+xtzdt/JVozuqFeqpqO2ez2e3G7WkRRl8PYfvBUAcP/xI/jUx2SSXSpBcWwjpNwJXRGH2RRjym9QECCKtNuTUaO2i4QOijbx5DLdjduVOuotuTZE1e7lF76D48elpNq994hJ97VvPGV+62ilje+z4hhZ2sZ2LHvNbcf2I1OgsnlZFMUSzb6D6TI8X8Yoy0k5NFXC/n0S3JBJS7/m9x9C2hax3CR2UaYJGW5vocJrxZL0Jev7SOXl/WsN2RJCxzUxdoqzrYctjhPEb6KowkCM7yLqy9llemEqa5vIMNa6E8oKTdmy8uywiQyRguERuf/HP/AwXC1jyG1KWYi4NG1ftgctPi3cgLPj6znbsxxEVKCef16CAe68Q8T0dqWFjQpjrXMiPkdKLhavCk49OSOY+oP334tTp0WRW1+TEKEMTR8PET74vvcAAIpMA8oUfJQI+Nx1Ut519A4RwUGriTbNMtdz+MxVnJ0XdG99lShiw8KH7r9D+qRRPj6zFQaoF6gMMtjBthyUy/L+SwSUQlcZjUwzseHsCEbp7EcDzt5F1Jez1zcEnFBBhJVN2a8yBWZTpBn4Z9WxtSQK1yPveT8A4MjBvWjSk5QwgNBOItgMsUkTSrV1cGHPmuvl8TDS8eU6gtSGTT1i/wFRCl899SoAYHl5C0fvuBsAMM/gvtbKNrKEeQt12WeTqII7jx0GAFSb0ofNNelnygbKGeHapQUJLqhuVvHAfT8AAHiGoUVffEHivGtRE6WMSLhP/+LPAwD+6okXcG5BINccsW4748PJSl9bLVH8nvnWtwAA9z/4blQo/TQQ5acyyPH+HEO3OpEykKuWiAk5Pe7xiPWjm2jjojBsVa7B93R4rnag80WlIuqhdODIXroz49hosHqiLMtCFOpsTG3Xanu3S5bSWggQcLIVO2VBIeBztUjLjYijYE+5gB+69wEAwOULYhV845knsFWVto1yQJMwwvKqLNyhEUH0jh6VYIrl7Toepct0+ZrUplOOj5N33QcA2G5Le5epscewoZgiVSWWXhybhtNgcIHDlCA3gMUwYMcSm6Rel9+dPXsWM5MSWdNpSt8SB4hiBjR4cn+rGSHmbIWU30nUxQcGYnxA11Ffzp6dEdciWk00tyV2qk40q5QV08HL5pB3Rdko0WVpo8dbgy7MoxUKRTz5DVdjz6VIe9F40XZsBDRTWnVBzg4Pi5mzXN1CipLg5CHh1Ftmp/DSOYmt1tUhWu2ORLP2XJuZEARvdGQU73nvQwCALdq+z7z4LJiHiExROHVsXPqZcjIYz9H0ItI1UkxhqEjuZZzeyrU1YzJqoTY5JQERC/PzmBiWscwXJIDD8x3Ua7LtOKDyqCyTCmxIV6uAQvwmzh8YcPYuov6JfVwttx4+jLnzwlFr6zRXiH6FjSbSeVGCRoaYJYLEcGMv1h3TlNLHYGjUp/dYDH0tSRJjeinVs++z0kEqJQpMkpN3x+0q6q4ohTodqZzN4tB+UeROnzvL72Kj6Djk8KtXpU+VShXr6+J5OnxIACLHC5HwJIo0vV57945z8CxErLKgA1VrW2tYmhedodlgPEAzQEzO1ghkhiDVlDeOs2zb4eN3ApCYdZ0W3GgJh9tuGvGOMdW6TIKk+10f6p8kwMHIea4pMVGr09nhSGNrlRqOHREbssBqDGEnAOgCTQwMmpjJ3llCUymFneegxHGMOL4+pcWyLASEIrO0gys5JhXUbGRCQZvqZ0STXrywjNy9dwEAUowQCdIRCtxuwFSiDi2HkZERDBOGLZWkL/NXruD3P/sHAIBbDhwFALS35T2W66LJQIkOh3Kr1sTKhiyAgNE9Odgm4CCidzShWprNZlCrypYxd1mCLw7O3gOXERNXdOyfHwFMn2JUNCzDGJGpJtFvSgdifBdRfzFOBnQtB9M0D2wuq7nFOQBA4ijMTkzxYTrjsIvV9iuEu1Oc77xmxH7PmtR4eZqZmC7NlatfeALntsWkWn5SkvPKuVEU3y6crfPJHd9DzGdokO/b3/42AGBmZgaTkyKiJyYkiGFmcgznXxS7eqq8DwBQXRPpNr9yDcOTYr7FHdnmSrkcpkfltyxIga2ry3jtrIjq2f2i9Ga5/YSdEOUhMR/XKwzIWF/DyJiM97UFiV2bODIEz6XjiNqYpV8QNpEYIVjAjWjA2buIbqKgdSsT7d0je/ZWTfaXgGlAnu2iyQACnbuddF5/Bkocx2/IyTtJ3xNHEWIqIDrfWimFkPE3DkEKvyHY9JnP/jFOjMk+69fEpMoMDZncbq0wJkliov4sIlFVJi3+6Z9+HgcOiitydo9Iq0O3TGMyI8M0PSHctv/WWWkX2qamSnVOTLx7D87g1ltk39eM96VHn8LlOdEjCsPCeW5GuD+bSmObZlaZVRw8zzWRpGCqkeMGcLWoNdk48l27vm5cxAPOHhCAm3B2hjix7zmYHJW9aea94hV64D4J/bEchbfddQ8AICLgoVQX9tQcFcexwbU1XWd67djjgyRGrIvkaUVTAQk1dK3dbrUF1x56+zFgmwUD6G+ulDzokgcahUUcGf+5TvvN0YystTuo0gfwzW9+m/1bRY0lLtfWBBsfnhaub1RX4VD6vLYsx4nESNBwdEoKPVahQoOa+dPPSFZJ2xEo+vjthzEyReCkpiWOBZuwqkMAyrMs+LYO4uS48d3FYtoEdfSjvpPts9yTBSDLcgkaoJ9keQkoB7NlEVvavlWWgpV0RS8gk2hZO67pSdQHJsiXMhhxaKrkURIjRmwWRYei96V//1kAQOn4bVieuwAAKDCBQXk5tFmFwWN0p1tNEHMrUK6OhGFhnE6E5QVxiX698QQAYHxvgKIlonFtQ7YnJyf9XVrdhs04thIL41UaTaxua3tYR7jY2LdfUp78jEzs6SuCSD777HPYf2QfAODWvRJg4aeyqLdERGvzN+vY8Lj4W9qMi2gCdpqmf/1oIMZ3EfVP7NP1PnuCkrVJFWhFybHhuNevqiRJDJiCHrBEc7QBUHo+VM9vAQm10Y+wepQsfSpUmrVdhvYx0U+5UKw2Z9M0cVMp836HwReFYtHkMiuH5TptkVZZL411RspeXZZ021xxDNMz4s1LpXWpSzGVls++igLj6X/43fcCAJ5/8SU8+YSkB8VM8TnxtmOYnhHlLpsVzj63IF61MEiw8Jq0Z+mibB0Pvf/tmNkrsfVVbk3nXn4GJ26Twnk+27uyKW217Q4ohPvSgLN3EfWvvGB191sNZnQ5LzL/1+movdi3sq43s5RSr9uz35Cz+VmpbJv7tE8c6Pq4a6uimA0vClcEoz42GeAXCl6BiUzavF9XUvB934QGKVaDcjwqRmEdKWZiHD0miXIH9+ZNdScnxWrEbNfYxCxyNIe0+TY6NoYjtwmuHkfC2cPj46aDYZtRq8TGXXvI6EOvzUkgxuWrGUzuEROwtiXK5qlXn8Q4a6yXGGIVtsTkvbhwBTH934du2Y8b0Zs+sU8Plhbj2kZVSiHNaBC/J0dYa+PaAeA4zuvs7F5z25R94v3NZstEt5ogh6SroDF2AltTIlrrG1soNWRwt5p0QKRSZpB121zHETsWQEzfZbPCMhrbl1AcuR0A8JGfkUoJpZzCmXMilscmxKly5twcAAlwyM4K4tZgWo+ybTNGIRf/6uY2bFtH28h3ZWLvUWIhkxZlbWVbJvbilTM4cYLVhTXaF8cIWZg+aAiC16aTJE5sDLO0SD8aiPFdRP3FOLkziGJTHCek10nnxA0Pjxl3o+b+JElMHfB6VVcQsN5AjPcobPx3aCRIDIdmjeaKJEkQMro0INeUjovIPP9nX0CGpl+FilHJc7vVZkhxHMOmspZl4Z/9E3SJPnAAr61JAMHQiHxXzA2jTVx7ZEy4+OF9ojyNlEfw6ukXAQAdjovtp9BmAX6NCZRHxxFpzICfRSb2wbGhoitsnLS1XotRrYliNjXNZIiZB1AuFDnOIrnWtkQidBpNWH5vcNcb04CzdxH152yDSUtIEIAuCsZNNp/PG67XCppt21D05n/py3KI/P3vfCdyOeEaIx3IzVEQwE569mUAiBKwvp6RMFEYGaWxyFjvRSpj9nAO0WXZy1TAZPtsRnzr8mD5QGy8aLWa3H+UWPbTc0/j/HmpgvDs8wKqePYYVjdlbzzPElnHjog0qWyuY2VZYsRPHhbv2ka1ijb712TK88bGBsJohGPqcIzYJ9hIOxIWlSLyNr+2jj/8o98FANx7n+zdnjNikhhfPS8nGbx4RvB4KwyQxCJBf/InPoAbUf8yG4rngag2ImVOBQEA4yb0Uj50cBTTnOGlFKpKOvrKouRf3Z/c3fUMuKzK0JYfXLx6GdstarOjElMWOx4sIlsWxbkKQ8TM/1oirPnkV74i71xewTp1+VYk3WoVbFMqxGGmWRAnCKhBh2zO3GVp61efm0PsiaYbMFJkbf0iGtR0PV8UtA4X9aOPP4bxkmxhpy9dNp8NOonWaDEc2zuNNIM9tBWTIdNU2jaqsThFCK5hr11HxBJkV68IvNpsthC05RmWJxFBgY5TsxzUqkQD+9BAjO8iukkJaqbuJF0nhybFIIatuIEX1+m+Y83QmUwZwbqsujHarW4ug2RBEJ+EwfNxnoHz568ixcD6Zkm4IXP37Qhp3ybEgjvtCGvr8v3amty/+KSYRTMh4DAsKtFbTjaFdYZR2aF0NeNnYdFE02Xiajwq4kCpiKs15k3z5KOFrU1TigotGYOQpt1QaQi3HhB0rUJnSXX5MqaneHBLSd45MZrC6uocAMCijT8xK1h5ZAO1NWnPOJG5zUI7MNcAABcESURBVPoKmA6P82ckAaNuJThx/J0AgNFhcbE22Z75+Us4evQW3IwGnL2LqC9nB8wvRhyb6gd1XXeUZ1bF559EmwDB8Xe9CwBw4fOPo3JVuOU2mg6Xv/k8nvvqswCAwl5xEY5+8AcBAAtzlzF0TsyI3H7ZM9tWT+uozDTDAKsM5tMlmlYyNMEiFx2yQ5AlF6c8JKwG0eb+n3J9tKjo2L5IjD17pI3RUg5b56RfHSp09z34IC6eEoVIe/JqrOcSWzbGGK61yiTBfdPTeOfdkiacoYSZ2DeL2pZIIo9KaUB0TSUWQppSi6virUslHlJMftSZN4nr48qC9N1WIgGmJ0SCOFaCXImmXB8acPYuor6c3WEeUzaTwRWGuS4viWniUxtv54dMjPP5p/9KHrq1jbUG9+BlCWPyl+bgzohUWF8Xj1L292U/KmZyeG2IuU2OcOK7wggOC+2GLFL3nReeN8c0nTh2HADwFaYOF+Gg3CC06LCw3OkraL4mEsalxOgUiliPhDN1HbGaqb4MJLZIsGtLwqkPvf/DOHP6FekrwZqmliAqxuI2w5IipiGnLXg50a5LWbELW00bK3pfZjBi2pdPL2MjpMkVMoMklS3ilr2SfHi+JsGTpVzRYOhpglj6CIp0OosiQ6D7Uf+DV/VRCJkMdPqdxrpBrPlMdQ31lihe9QUZhFySmMQ+p8aMzXaEFovP+64+PUcGdgNtc47jZkNE1Ua9ihkdQbIiyk/QauPEnWLPZlLS0Rm6DtdeOYNHDkv0zLUlmeDgG6/gGisizFJ5w/5Zk0utS4dsbtMUs2Pk8tK2dJ3x2s0mEsaBWSwC6HDx2a0mLlwQ9KtSlXv8lINUUZA2RTFebzawVpHxKI5In/xEJixsB4jpkLn1pPTND5uosrzW8ROyJaTdNMJQlN5UStof8/TElJ8B+Lx+NBDju4huEl1KEwaWOZNLBw90CA40lULUYviNy1hoO0Jarzq+oplzMFJjCgyjNVuMD+sEHSieo6nBjGR5G96QrMUVHj2xf2YWHiWKdrlOCxaD880WtmhL5T8gMXH5uoX9FERLRN4unj6DiMqdxt6XL4lYH0nZmC4Kh7RfEnTqlS9+GRvcwoaq9A9QeUqvVbCHxzefpgJWTJeRpkRsN+W5jaCJkRnhdrcov12rU9EMI2i8qm1pd2wVTz8pymwrFklwx22HceWqbH+Hjx7muBEVtFPYN6NTr25MA87eRdQfG9dx4LZlsvy1PzlkBoQf21Da56qD+2wbMaHLOpP4A89CzAhLDVKE3Hucho1SnUAL8Yul1ha2LsvqP3VGMjJ+9hc+iYReryxjp6fLouhsj01j+ZwofOlX5XM9iRDn5L454tUX2m00mSTP7uG+Q9KO4ckUilm5ePaygDdPPvccFOHVrWUxDwMqgFanjQ7ztO6juRUlAba3WLGCCqDt2iizbkqDR09EOtQrTgxur/RxVGGMPE/vHdUFEaqrGB3X56ESV2fA4bnzF7CyLnrNHQc/ghtR/8nmURHXZQiaOmXdDMIOqwcaR0igTPxahy7OlJ8y+cVBVRSNdIeZmLaNZYo87XzZ2FzHAcZhjeyX6IvYtqBo+7/4lIT1xqy88P4f+xTyLfnt6mnJopy9+wg2l6XkRn5bBjm3uYVTSxL/NcxokVFfFEzHWsXomFxbmBFRmdp7GJ2GDOTV83MAgMMHBK1SuTQmZgXNmt0jaT315raJZHHoQk35DjaYHaonSsdthGEIxYCGmGJ5a7OCJpVHT+nS3y5atAKaLY1/8ByT8VE0O4NzvQbUQ/2L3ulwoDjuFqbTIUW8x7YstBmtWR4fNffrqsFDrAaoev7WbkpdJ3S7so3RkVE+kZ6rWgPTPK5h/0HhpHq1hrM8nGXxgnjT3BrNoGrVHFqzOUTFz4tQW5d2OFSqykM+pomNj42JVHj+Mo+XnLuC24+J+9Kbkhi0kdEcFpeIFQxLX4r7hZvHvARH7xTxPVSWZ3WCmgl72qJrNI5D5JhiXKOnqk7TLoxCg/wVGJzge2lcuCD+hvkrYto1m03cdtttAIDJSfEMtmgGu66NCDcvSzzg7F1E/euNcw+OVWLCabpRoDpbo1uyTjvr06mUCUJMaIIp2+qGkGu3NuPBc6mMSWXR0qRVr6PG+qE5R9crLUNxzzszJ/uyIjdffullHJgWgEUfqfzoX/wFbMZYz84Kjry4cAUZnsD37HOSsuP5wiknxifQYNXll68KUvjR+0/i0qJkiRy+S4reDe2RZ4WbSyiOiMnzJ3/yJwCAAwemceyocGCtvs0OK7Qo/TRHa25utVvwiYzpa5ZycPfdUuZrY2PDjG0+zyBFHcSpKxvbNjrhwJ89oB7q7/WiuaLgmNP7bBMr2K3voUOVdNiM67pIE/wIqSU6sEz9M51NosN7s/kc2m1dFpKHxUURWryWg+x3jm1jhX7sazxGyWUdlyMzM3jHPZIx8cozAkhMOQXkS4IZn9wvJTJqQ1PmYPaX2M8Xrom2jcJerLSFGzfrorFfWb6MddY9m6Lmrf3loxMTaDPc5VtPPs3hOIHJcfFx6yiZKFYmfFqPlf4cHxuHy4PU9Ri0W4EpppvNClKUz+eRY3kQHbipw7ualQp85+a5Xn0nW4se2+rGX2vlCj1Zg1pkr1dlUFrNJiIOgjbBms2OmVzd2BoxZtdxEOsT9ehscJIYDQbBWxZPAUoUNjbF9rZ4rtdeiu6f+tEfR0RR9uGP/JTcH8WIaV6dp0JXW4xwlfay4qRUX3gZAPBnpxeQ6LPAA5n0v/xyglKaJ/Bwv9KZlX5sY21N2pOmiHV9D7W6KHQd5o5XG23DCHprNDH2SYIseDgMxXMQdBBoZwsn1LIsU5BeL4BpZpMuLa8geRNCeiDGdxH1D0uiuA2iCJajz3Mi0sVVHsQRPAY0+K1udpkWU8rWJSy7Sp0+GF2v5E4Um6oNWslrtWOsbYh43btvH9/dTRjM8bCVn/yxRwAAG0tL6BDoGWYRO1cl2KqItPlXn/kMAGDuyjw81mPJEKU6Snz7q1dWELJm5GxROLVcHkOnQgBel9UMNaK2hr0EftL0wi3MX0WZMeFBkym1TgouqzW5jLpNMTHRsi1UWVO8xgCRRqONIOjG4AOSQNmJ6V1kaU6XoVPZQhmrK+u4GQ04exdRf9OLXNzqRLDp0bJp6vjcCx0HKJFDdCrs+vo6MhnZr0x+FxIT/60TAVP0Kzu2hYT+26w+vCxSaDK3KeGJgHNXLqFBUMKnpLnMakJLi4t4/0MPAwAqy6K8FQolPP+chBRduSR4uWu78Hkge57HUCXMd80XPdQrwj1tW9rfrK4apXRiQkCVNpPzXN9BlTrE9IgGlKrm9NsUgxdcx4NNPN4h4DK/IDDulauLWGNdtfUNnkgcxEhY80x79zzPM2Op4+91Jk51ewsx66v80t/9BG5E/cW4Obo3Rpsn9Wkx5FaY71zIGIVLi+477rijq9zx2tramlFKtJKii7bV6w2zZej74zhGhXHXNVZSePX0aWwzpkxHmX7+c58DAHz0p38GswxkCBiPbtkWHnv8cbZbBnlsbMxsFavU7DtUyjKZnNFqh3gcxa233oaAfSky+lPHoO3ZM4sqRe/WNisjHp5BhiLaFPnxU8a/0Amut0RmZ2aQyYhCp7itbdcaaDS03Sxj2+m0UaAzRSttGt/odNrYpCOkHw3E+C6ivpzdpN0XRVE3R5pVrzT+C0TGJgxpbp0+fcZUOhgfF2XJcVxMMhJTKx1lnlWZTacNZjwzI7ZsJp3GmZclX/n5J+Xknn0HD+A5SoUDtwhevndKnvn2u+8xSp7+nLs8jwsXpM7KHnqlhCuIv1OBatILNjJcRo2VinNE3A4fOYpnnnoKANBh/zRHjYyOYHFJkv4qNDtdb5+Rfp7TlWT6t1qx1eZTKh2jSLNtlJjB8uo6Vldle6jTlVzvRGg0auZ5Mgc829RxjGTsRwPO3kXUl7N7U3CjnUVmuaVsblYMJ+mQoXarjQQiFWrVi+Z3V64IxmyZYyAY3Od7cLhXnj4t4UCFYhGJDnbg3nf+0gWjC/ydT34SAHD3cYkyVVYXo9cQ/Ne/+U2DLU+xvne5XDbIk0vp5PP8slq1YSoV17kvNxoteL6uAy4Kl/YnV2o1fP0bjwEAVpZFAXScO03CYr2ugZTIlHxqUQq2ybFhFJraKwH92aViAZm0mJYN7vGR42HpmgRSmsJ/1EM828Y2dap+1B8ujbtHP+iyGboctHbQJ3FixHiTgQW+7xnkzCBub0CxOaMrQIu249aWiFG1sGhqqHX00c5RhHvukfiyWUKXeuHEcWIGuUIHyqnTr6LMbE+9SPbs2YODdJl+6VFJCixQ8Wo26lhjVub8vEze5z7355ieFpF+dVG+W6AF8Jdf+HOjhN16q9jb2WwGDTo79LEOCkCjLRPfZlZppMtHK4VOS2+Dcq3WqGGFCQNXaVmEPRUuMlycY3QpT46NY3119YbjrGkgxncR3aSAjj6cRZkjHswBL/oUPd83B6ln+Lm1tYVtKjra5NEKG9A1rxxTFcEy5zJ6brcuS4exagFjuQqFIkbGZDVv8FCXMlEkZSk4RPJefkWC+s++dh4zk8KVWpw7jmOc/xr1WiH32HZ3y8jlMvzdJq4tsUDdc+Jg8em4eOih9+AHHpCUp5Ul2aJWV64i1ik7oa4rE6JN0atNL52n3QlChCzl1eJ3W5UatriNaAkaxSG2WCZrm6hgg3H3m+vr8NybO0IGnL2LqL+Cxtog2Wy2i3qldJ1suuB8z5Rt1EcklwtZNFgZOGRSeaeTIIyvd7p7ROMsZV13JBRAScDt3tTljBNcYZjOudfEi6UPXSkPDRlk6WtfEyCl0+qgydWvD3E9e+40XFe419Ox6uQYCwq3HhGc/ARrtShlGRBGBx6Mj0sM+AMPvAtzF0UB3SBAE8Wx8fjpsKtObBmTK2ZyYKfdBaw03p/NSnty+QlMTYlrdo5K7cLKpolI1VK2QkAHSCGXLeFmNODsXUR9OVsXZiuXCqbCkF7dKW22+I7ZL0pl0XxHhkdw4IAk0tWZHLhdreDiZQmia5BTuPBhwQIrdJj9PIxCgyNrrg/CEAssJPvFL35ROkBzKJ/Lo8z3n2KtkVQmbWq0GG9TKoWxCfFju4xHnxgTLsr6Lt75Dsm3ypPLojBCeb+uQS4WgLYYXnzu+Z76cLQcekJ6NQcmsEw4VUQMO+wxa21HWzrSVse2UeBh9Pp8072bNaxR71i8JjrEOv8fxwHS6a6ucyPqO9kH2LkoilBi9KTvi8Kj8V+oxBSD0eZWHEdI8eUNmmNr6xtYoqKjzTiPzoFMOmMUOYObW5YZEFMYXsVmO9GLosPi7strDaysE+tmvrPtdgvt6d/dd999OHqrxIid5aK45YCga45SyDBxwWUb84Ui9u3ZBwCYn5ctZJ24vGPZBjXUh8qI+ddVqjTpWiq6f5osqxubp5VD13VNwSK91R2YGcOeKVmk48MyF5fmpD3tIMLw0M0neyDGdxH15ewR5vwqpUxko+aUgEBHJ+iYa5E5lU5hm6UZl+lUbzXbKJWG+BsWiFM6jtwyWLEGDhzHMYEPesWHQYAUV7q5vyBI0/DICLIEG6rMOLk8N4c2USztZdq3bx8Wr0nkqI4ydagg5bNppFi32xzK3mrj5ZdfMe+XvmtgJDbF7BITY5+YsemNztWRozuPu5KfdccBEKml+xxrz2McGnRv/6yggWM86S9RCncyGrUfDTh7F1Ffzl5dF0VkYX6hG2akYVOuRj/lGjDFT+kDTTyNkWCSh6gcLOTN0tKnxOqKCtVKpRvJqjSAUkCO/lt9sFq71cIWc6Z87vHDY5Lsls/nMcJTczWAc/jAfpw9cw5AV7F8+umnu5xJU2bxmlRZyOVypqpBhoeZI7FMX0zBXK1ExjEiU/VYf8bdM0aZ8hyGWv18/amFwOurNUsVaB45Qc6GbZmo2E5TH6quJR8wOVLEzai/nc385eLwKOqMjtxiZMYSRWGjUjEN0yI4n8+jUBQlQit2hXIRLkVpmuUhsozkGB8fN4vJhNO226gwakR3OApCbPP9ka5hqhdMJoPFOcmj1spYgu5JgFqMR2Fo3mUxFi3kSX8bWxXEiQQSZLLdsF2d2qMdPRovSGzLKF69TiOteXfYlzju+hRsLZ6TrqK2c7KjKDK2d4p9UUoZB4zt8txxc2ylQoNbF0ZwQxqI8V1ENzn9R8RoPj+EDtG0CZ4kd/yYJLTZSYwqc5S1SbKwcNUcZnrxkiBMfjqFEZ4gNDQkYlnbhrbdjYnWHp2Un4JHO1/XGvVcD4qcsc0DT9vMd86k0kjzt/oZjusi7FGcAPF+6WjYlAkykE/lp9AJ9LEUzKdu1NFoMQzIiGXh4qmpKWO+ae+e7/kGQVO837J7Ey6ojNm9nH791mhZtjG5NPdGSdJ9v07oc7r4uk6o6EcDzt5F1D8sqdENGtT7ig6F0cpBynNRZFruLI86OPm2uwzYoSv/rq6umn1+fUXAFe05y+ZyZk9tMQXX8zzErKBka65Pp41eMMtY8oh+4ma9jk3u8VX6syenp42eoCsnZ/O5nlMBGUjQ7Fbk98nRMTk8aEdogEl51SZ/R+73ckilxQQ0YEmirjMpASBQEdye9Gc9pgCP0zA8p7nd6TkHS+5LEBvwSpNFadWJAlN/vR/1nexCQVfZC43o0Jpl3FM+WitV5kwP20arLQPTpgI1MjKKmRlB33SwS5PVFq5dW8LKisSBrQXiusxkMiho1I73VzoBKtuyZWglzOGgeZ6HDE+Wt0yCgm8CAzZYGTGOI4P0IWHECgvXeH7GRM9UWsy2DDvI8bkVnSxAurIwL2eN9bQn5Tjd8631p/v6AA5zdEYcmwzMpKUXggPf16VAunFmO5FK9ASGVKrbuBkNxPguov5hSWFXjOt46oSB/ToOKmpHJpymN+ZbKw+ep5PiYhO2pBEmTXv27MXBgwcBdDNBFxcXsbomXK4lWqFQQDbDYAUTaSbvqVQbxvzRK39zs4JSUUyoXjOlTW5vUHzrQjS5QgltuiB1zFja903qkza5tNlkJbZRXHW4UcdxTEE+vU3FQdxjVzMDM+yxt3VKlRbLrTaqxAUsEyximaSALF256RQlb5KgWq/hZjTg7F1EfTm7Qfek4zgGldq5b7gp+zpAQZPWFwxOpCxzyp6uHaLvbzab2OTpc3ol79t3AIcOSV0TfWbW3KVLmL8saTP6nUXiwyMjI/B9Xa2fZ1a2Wri8pTNZWKUgnTY4/1heYtoTloKo1evY3GQVY+omQ6WSCZ5oUyJ1ce3Q4PyKIE8rSRAwclSjccpSZtxMwCZDkcI40gWoDGcnyoJPrjXXkhg1KsyV2o7035TTPSGxDw04exdRX85u68r5dgLHuX5f1vGDnq169qM3ILPglOH2TrubYA4A2WzO5FFp8KFarRrN26W+cOKOk+Y3i4sC2ly6LKDN2VdPmT1tilWWCsUiPPd6IKTT6WCZyfjaLMgRvvXTXa9Xmh4x27Iwf3Xhui5piySTyUAxAU9LPseyDF7epqfLcWx0OjtNLss8K9pZzQIwJmOLOHgM8c8DgG0OvGO2SKODc+ev4GbUP7FP18aM4p7EO5op2npx4utsxp1kIlTx+iMYtYhqtzoI7e7JfgBRtkREtE4NWltbN67CYYrvQwd/CIA4OjRad/GCfIZxjNm9ElOWSmuR6iDNgjUaX29zu6psV2Gb+DS5P1fImbJWOvZcK2hhFBn8W8ebOZaNESKEdpoIVyfoFsd5Axxcec513yVJYkxFrwcb12K7q4hqu9w1ymA/GojxXUSqV6ka0P/fNODsXUSDyd5FNJjsXUSDyd5FNJjsXUSDyd5F9H8BhhjvR2xHxL4AAAAASUVORK5CYII=\n",
      "text/plain": [
       "<Figure size 144x144 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "show_image(x, title=lbls[y]);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As you see, our dataset is returning the independent and dependent variables as a tuple, which is just what we need. We'll need to be able to collate these into a mini-batch. Generally this is done with `torch.stack`, which is what we'll use here:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def collate(idxs, ds): \n",
    "    xb,yb = zip(*[ds[i] for i in idxs])\n",
    "    return torch.stack(xb),torch.stack(yb)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here's a mini-batch with two items, for testing our `collate`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(torch.Size([2, 64, 64, 3]), tensor([0, 0]))"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x,y = collate([1,2], train_ds)\n",
    "x.shape,y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that we have a dataset and a collation function, we're ready to create `DataLoader`. We'll add two more things here: an optional `shuffle` for the training set, and a `ProcessPoolExecutor` to do our preprocessing in parallel. A parallel data loader is very important, because opening and decoding a JPEG image is a slow process. One CPU core is not enough to decode images fast enough to keep a modern GPU busy. Here's our `DataLoader` class:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class DataLoader:\n",
    "    def __init__(self, ds, bs=128, shuffle=False, n_workers=1):\n",
    "        self.ds,self.bs,self.shuffle,self.n_workers = ds,bs,shuffle,n_workers\n",
    "\n",
    "    def __len__(self): return (len(self.ds)-1)//self.bs+1\n",
    "\n",
    "    def __iter__(self):\n",
    "        idxs = L.range(self.ds)\n",
    "        if self.shuffle: idxs = idxs.shuffle()\n",
    "        chunks = [idxs[n:n+self.bs] for n in range(0, len(self.ds), self.bs)]\n",
    "        with ProcessPoolExecutor(self.n_workers) as ex:\n",
    "            yield from ex.map(collate, chunks, ds=self.ds)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's try it out with our training and validation datasets:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(torch.Size([128, 64, 64, 3]), torch.Size([128]), 74)"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "n_workers = min(16, defaults.cpus)\n",
    "train_dl = DataLoader(train_ds, bs=128, shuffle=True, n_workers=n_workers)\n",
    "valid_dl = DataLoader(valid_ds, bs=256, shuffle=False, n_workers=n_workers)\n",
    "xb,yb = first(train_dl)\n",
    "xb.shape,yb.shape,len(train_dl)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This data loader is not much slower than PyTorch's, but it's far simpler. So if you're debugging a complex data loading process, don't be afraid to try doing things manually to help you see exactly what's going on.\n",
    "\n",
    "For normalization, we'll need image statistics. Generally it's fine to calculate these on a single training mini-batch, since precision isn't needed here:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[tensor([0.4544, 0.4453, 0.4141]), tensor([0.2812, 0.2766, 0.2981])]"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "stats = [xb.mean((0,1,2)),xb.std((0,1,2))]\n",
    "stats"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Our `Normalize` class just needs to store these stats and apply them (to see why the `to_device` is needed, try commenting it out, and see what happens later in this notebook):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Normalize:\n",
    "    def __init__(self, stats): self.stats=stats\n",
    "    def __call__(self, x):\n",
    "        if x.device != self.stats[0].device:\n",
    "            self.stats = to_device(self.stats, x.device)\n",
    "        return (x-self.stats[0])/self.stats[1]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We always like to test everything we build in a notebook, as soon as we build it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "norm = Normalize(stats)\n",
    "def tfm_x(x): return norm(x).permute((0,3,1,2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([0.3732, 0.4907, 0.5633]), tensor([1.0212, 1.0311, 1.0131]))"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t = tfm_x(x)\n",
    "t.mean((0,2,3)),t.std((0,2,3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here `tfm_x` isn't just applying `Normalize`, but is also permuting the axis order from `NHWC` to `NCHW` (see <<chapter_convolutions>> if you need a reminder of what these acronyms refer to). PIL uses `HWC` axis order, which we can't use with PyTorch, hence the need for this `permute`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "That's all we need for the data for our model. So now we need the model itself!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Module and Parameter"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To create a model, we'll need `Module`. To create `Module`, we'll need `Parameter`, so let's start there. Recall that in <<chapter_collab>> we said that the `Parameter` class \"doesn't actually add any functionality (other than automatically calling `requires_grad_` for us). It's only used as a \"marker\" to show what to include in `parameters`.\" Here's a definition which does exactly that:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Parameter(Tensor):\n",
    "    def __new__(self, x): return Tensor._make_subclass(Parameter, x, True)\n",
    "    def __init__(self, *args, **kwargs): self.requires_grad_()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The implementation here is a bit awkward: we have to define the special `__new__` Python method and use the internal PyTorch method `_make_subclass` because, as at the time of writing, PyTorch doesn't otherwise work correctly with this kind of subclassing or provide an officially supported API to do this. This may have been fixed by the time you read this, so look on the book's website to see if there are updated details.\n",
    "\n",
    "Our `Parameter` now behaves just like a tensor, as we wanted:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(3., requires_grad=True)"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Parameter(tensor(3.))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that we have this, we can define `Module`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Module:\n",
    "    def __init__(self):\n",
    "        self.hook,self.params,self.children,self._training = None,[],[],False\n",
    "        \n",
    "    def register_parameters(self, *ps): self.params += ps\n",
    "    def register_modules   (self, *ms): self.children += ms\n",
    "        \n",
    "    @property\n",
    "    def training(self): return self._training\n",
    "    @training.setter\n",
    "    def training(self,v):\n",
    "        self._training = v\n",
    "        for m in self.children: m.training=v\n",
    "            \n",
    "    def parameters(self):\n",
    "        return self.params + sum([m.parameters() for m in self.children], [])\n",
    "\n",
    "    def __setattr__(self,k,v):\n",
    "        super().__setattr__(k,v)\n",
    "        if isinstance(v,Parameter): self.register_parameters(v)\n",
    "        if isinstance(v,Module):    self.register_modules(v)\n",
    "        \n",
    "    def __call__(self, *args, **kwargs):\n",
    "        res = self.forward(*args, **kwargs)\n",
    "        if self.hook is not None: self.hook(res, args)\n",
    "        return res\n",
    "    \n",
    "    def cuda(self):\n",
    "        for p in self.parameters(): p.data = p.data.cuda()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The key functionality is in the definition of `parameters`:\n",
    "\n",
    "```python\n",
    "self.params + sum([m.parameters() for m in self.children], [])\n",
    "```\n",
    "\n",
    "This means that we can ask any `Module` for its parameters, and it will return them, including for all its child modules (recursively). But how does it know what its parameters are? It's thanks to implementing Python's special `__setattr__` method, which is called for us any time Python sets an attribute on a class. Our implementation includes this line:\n",
    "\n",
    "```python\n",
    "if isinstance(v,Parameter): self.register_parameters(v)\n",
    "```\n",
    "\n",
    "As you see, this is where we use our new `Parameter` class as a \"marker\"—anything of this class is added to our `params`.\n",
    "\n",
    "Python's `__call__` allows us to define what happens when our object is treated as a function; we just call `forward` (which doesn't exist here, so it'll need to be added by subclasses). Before we do, we'll call a hook, if it's defined. Now you can see that PyTorch hooks aren't doing anything fancy at all—they're just calling any hooks have been registered.\n",
    "\n",
    "Other than these pieces of functionality, our `Module` also provides `cuda` and `training` attributes, which we'll use shortly.\n",
    "\n",
    "Now we can create our first `Module`, which is `ConvLayer`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ConvLayer(Module):\n",
    "    def __init__(self, ni, nf, stride=1, bias=True, act=True):\n",
    "        super().__init__()\n",
    "        self.w = Parameter(torch.zeros(nf,ni,3,3))\n",
    "        self.b = Parameter(torch.zeros(nf)) if bias else None\n",
    "        self.act,self.stride = act,stride\n",
    "        init = nn.init.kaiming_normal_ if act else nn.init.xavier_normal_\n",
    "        init(self.w)\n",
    "    \n",
    "    def forward(self, x):\n",
    "        x = F.conv2d(x, self.w, self.b, stride=self.stride, padding=1)\n",
    "        if self.act: x = F.relu(x)\n",
    "        return x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We're not implementing `F.conv2d` from scratch, since you should have already done that (using `unfold`) in the questionnaire in <<chapter_foundations>>. Instead, we're just creating a small class that wraps it up along with bias and weight initialization. Let's check that it works correctly with `Module.parameters`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "l = ConvLayer(3, 4)\n",
    "len(l.parameters())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And that we can call it (which will result in `forward` being called):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([128, 4, 64, 64])"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "xbt = tfm_x(xb)\n",
    "r = l(xbt)\n",
    "r.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the same way, we can implement `Linear`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Linear(Module):\n",
    "    def __init__(self, ni, nf):\n",
    "        super().__init__()\n",
    "        self.w = Parameter(torch.zeros(nf,ni))\n",
    "        self.b = Parameter(torch.zeros(nf))\n",
    "        nn.init.xavier_normal_(self.w)\n",
    "    \n",
    "    def forward(self, x): return x@self.w.t() + self.b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "and test if it works:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([3, 2])"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "l = Linear(4,2)\n",
    "r = l(torch.ones(3,4))\n",
    "r.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's also create a testing module to check that if we include multiple parameters as attributes, they are all correctly registered:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class T(Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.c,self.l = ConvLayer(3,4),Linear(4,2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Since we have a conv layer and a linear layer, each of which has weights and biases, we'd expect four parameters in total:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t = T()\n",
    "len(t.parameters())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We should also find that calling `cuda` on this class puts all these parameters on the GPU:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "device(type='cuda', index=5)"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t.cuda()\n",
    "t.l.w.device"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can now use those pieces to create a CNN."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Simple CNN"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As we've seen, a `Sequential` class makes many architectures easier to implement, so let's make one:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Sequential(Module):\n",
    "    def __init__(self, *layers):\n",
    "        super().__init__()\n",
    "        self.layers = layers\n",
    "        self.register_modules(*layers)\n",
    "\n",
    "    def forward(self, x):\n",
    "        for l in self.layers: x = l(x)\n",
    "        return x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `forward` method here just calls each layer in turn. Note that we have to use the `register_modules` method we defined in `Module`, since otherwise the contents of `layers` won't appear in `parameters`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> important: All The Code is Here: Remember that we're not using any PyTorch functionality for modules here; we're defining everything ourselves. So if you're not sure what `register_modules` does, or why it's needed, have another look at our code for `Module` to see what we wrote!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can create a simplified `AdaptivePool` that only handles pooling to a 1×1 output, and flattens it as well, by just using `mean`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class AdaptivePool(Module):\n",
    "    def forward(self, x): return x.mean((2,3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "That's enough for us to create a CNN!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def simple_cnn():\n",
    "    return Sequential(\n",
    "        ConvLayer(3 ,16 ,stride=2), #32\n",
    "        ConvLayer(16,32 ,stride=2), #16\n",
    "        ConvLayer(32,64 ,stride=2), # 8\n",
    "        ConvLayer(64,128,stride=2), # 4\n",
    "        AdaptivePool(),\n",
    "        Linear(128, 10)\n",
    "    )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's see if our parameters are all being registered correctly:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "10"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m = simple_cnn()\n",
    "len(m.parameters())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can try adding a hook. Note that we've only left room for one hook in `Module`; you could make it a list, or use something like `Pipeline` to run a few as a single function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.5239089727401733 0.8776043057441711\n",
      "0.43470510840415955 0.8347987532615662\n",
      "0.4357188045978546 0.7621666193008423\n",
      "0.46562111377716064 0.7416611313819885\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "torch.Size([128, 10])"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def print_stats(outp, inp): print (outp.mean().item(),outp.std().item())\n",
    "for i in range(4): m.layers[i].hook = print_stats\n",
    "\n",
    "r = m(xbt)\n",
    "r.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We have data and model. Now we need a loss function."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Loss"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We've already seen how to define \"negative log likelihood\":"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def nll(input, target): return -input[range(target.shape[0]), target].mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Well actually, there's no log here, since we're using the same definition as PyTorch. That means we need to put the log together with softmax:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(-1.2790, grad_fn=<SelectBackward>)"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def log_softmax(x): return (x.exp()/(x.exp().sum(-1,keepdim=True))).log()\n",
    "\n",
    "sm = log_softmax(r); sm[0][0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Combining these gives us our cross-entropy loss:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(2.5666, grad_fn=<NegBackward>)"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "loss = nll(sm, yb)\n",
    "loss"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that the formula:\n",
    "\n",
    "$$\\log \\left ( \\frac{a}{b} \\right ) = \\log(a) - \\log(b)$$ \n",
    "\n",
    "gives a simplification when we compute the log softmax, which was previously defined as `(x.exp()/(x.exp().sum(-1))).log()`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(-1.2790, grad_fn=<SelectBackward>)"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def log_softmax(x): return x - x.exp().sum(-1,keepdim=True).log()\n",
    "sm = log_softmax(r); sm[0][0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then, there is a more stable way to compute the log of the sum of exponentials, called the [LogSumExp](https://en.wikipedia.org/wiki/LogSumExp) trick. The idea is to use the following formula:\n",
    "\n",
    "$$\\log \\left ( \\sum_{j=1}^{n} e^{x_{j}} \\right ) = \\log \\left ( e^{a} \\sum_{j=1}^{n} e^{x_{j}-a} \\right ) = a + \\log \\left ( \\sum_{j=1}^{n} e^{x_{j}-a} \\right )$$\n",
    "\n",
    "where $a$ is the maximum of $x_{j}$.\n",
    "\n",
    "\n",
    "Here's the same thing in code:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(True)"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = torch.rand(5)\n",
    "a = x.max()\n",
    "x.exp().sum().log() == a + (x-a).exp().sum().log()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We'll put that into a function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(3.9784, grad_fn=<SelectBackward>)"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def logsumexp(x):\n",
    "    m = x.max(-1)[0]\n",
    "    return m + (x-m[:,None]).exp().sum(-1).log()\n",
    "\n",
    "logsumexp(r)[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "so we can use it for our `log_softmax` function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def log_softmax(x): return x - x.logsumexp(-1,keepdim=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Which gives the same result as before:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(-1.2790, grad_fn=<SelectBackward>)"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sm = log_softmax(r); sm[0][0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can use these to create `cross_entropy`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def cross_entropy(preds, yb): return nll(log_softmax(preds), yb).mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's now combine all those pieces together to create a `Learner`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Learner"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We have data, a model, and a loss function; we only need one more thing we can fit a model, and that's an optimizer! Here's SGD:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class SGD:\n",
    "    def __init__(self, params, lr, wd=0.): store_attr()\n",
    "    def step(self):\n",
    "        for p in self.params:\n",
    "            p.data -= (p.grad.data + p.data*self.wd) * self.lr\n",
    "            p.grad.data.zero_()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As we've seen in this book, life is easier with a `Learner`. The `Learner` class needs to know our training and validation sets, which means we need `DataLoaders` to store them. We don't need any other functionality, just a place to store them and access them:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class DataLoaders:\n",
    "    def __init__(self, *dls): self.train,self.valid = dls\n",
    "\n",
    "dls = DataLoaders(train_dl,valid_dl)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we're ready to create our `Learner` class:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Learner:\n",
    "    def __init__(self, model, dls, loss_func, lr, cbs, opt_func=SGD):\n",
    "        store_attr()\n",
    "        for cb in cbs: cb.learner = self\n",
    "\n",
    "    def one_batch(self):\n",
    "        self('before_batch')\n",
    "        xb,yb = self.batch\n",
    "        self.preds = self.model(xb)\n",
    "        self.loss = self.loss_func(self.preds, yb)\n",
    "        if self.model.training:\n",
    "            self.loss.backward()\n",
    "            self.opt.step()\n",
    "        self('after_batch')\n",
    "\n",
    "    def one_epoch(self, train):\n",
    "        self.model.training = train\n",
    "        self('before_epoch')\n",
    "        dl = self.dls.train if train else self.dls.valid\n",
    "        for self.num,self.batch in enumerate(progress_bar(dl, leave=False)):\n",
    "            self.one_batch()\n",
    "        self('after_epoch')\n",
    "    \n",
    "    def fit(self, n_epochs):\n",
    "        self('before_fit')\n",
    "        self.opt = self.opt_func(self.model.parameters(), self.lr)\n",
    "        self.n_epochs = n_epochs\n",
    "        try:\n",
    "            for self.epoch in range(n_epochs):\n",
    "                self.one_epoch(True)\n",
    "                self.one_epoch(False)\n",
    "        except CancelFitException: pass\n",
    "        self('after_fit')\n",
    "        \n",
    "    def __call__(self,name):\n",
    "        for cb in self.cbs: getattr(cb,name,noop)()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This is the largest class we've created in the book, but each method is quite small, so by looking at each in turn you should be able to follow what's going on.\n",
    "\n",
    "The main method we'll be calling is `fit`. This loops with:\n",
    "\n",
    "```python\n",
    "for self.epoch in range(n_epochs)\n",
    "```\n",
    "\n",
    "and at each epoch calls `self.one_epoch` for each of `train=True` and then `train=False`. Then `self.one_epoch` calls `self.one_batch` for each batch in `dls.train` or `dls.valid`, as appropriate (after wrapping the `DataLoader` in `fastprogress.progress_bar`. Finally, `self.one_batch` follows the usual set of steps to fit one mini-batch that we've seen throughout this book.\n",
    "\n",
    "Before and after each step, `Learner` calls `self`, which calls `__call__` (which is standard Python functionality). `__call__` uses `getattr(cb,name)` on each callback in `self.cbs`, which is a Python built-in function that returns the attribute (a method, in this case) with the requested name. So, for instance, `self('before_fit')` will call `cb.before_fit()` for each callback where that method is defined.\n",
    "\n",
    "As you can see, `Learner` is really just using our standard training loop, except that it's also calling callbacks at appropriate times. So let's define some callbacks!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Callbacks"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In `Learner.__init__` we have:\n",
    "\n",
    "```python\n",
    "for cb in cbs: cb.learner = self\n",
    "```\n",
    "\n",
    "In other words, every callback knows what learner it is used in. This is critical, since otherwise a callback can't get information from the learner, or change things in the learner. Because getting information from the learner is so common, we make that easier by defining `Callback` as a subclass of `GetAttr`, with a default attribute of `learner`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Callback(GetAttr): _default='learner'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`GetAttr` is a fastai class that implements Python's standard `__getattr__` and `__dir__` methods for you, such that any time you try to access an attribute that doesn't exist, it passes the request along to whatever you have defined as `_default`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For instance, we want to move all model parameters to the GPU automatically at the start of `fit`. We could do this by defining `before_fit` as `self.learner.model.cuda()`; however, because `learner` is the default attribute, and we have `SetupLearnerCB` inherit from `Callback` (which inherits from `GetAttr`), we can remove the `.learner` and just call `self.model.cuda()`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class SetupLearnerCB(Callback):\n",
    "    def before_batch(self):\n",
    "        xb,yb = to_device(self.batch)\n",
    "        self.learner.batch = tfm_x(xb),yb\n",
    "\n",
    "    def before_fit(self): self.model.cuda()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In `SetupLearnerCB` we also move each mini-batch to the GPU, by calling `to_device(self.batch)` (we could also have used the longer `to_device(self.learner.batch)`. Note however that in the line `self.learner.batch = tfm_x(xb),yb` we can't remove `.learner`, because here we're *setting* the attribute, not getting it.\n",
    "\n",
    "Before we try our `Learner` out, let's create a callback to track and print progress. Otherwise we won't really know if it's working properly:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TrackResults(Callback):\n",
    "    def before_epoch(self): self.accs,self.losses,self.ns = [],[],[]\n",
    "        \n",
    "    def after_epoch(self):\n",
    "        n = sum(self.ns)\n",
    "        print(self.epoch, self.model.training,\n",
    "              sum(self.losses).item()/n, sum(self.accs).item()/n)\n",
    "        \n",
    "    def after_batch(self):\n",
    "        xb,yb = self.batch\n",
    "        acc = (self.preds.argmax(dim=1)==yb).float().sum()\n",
    "        self.accs.append(acc)\n",
    "        n = len(xb)\n",
    "        self.losses.append(self.loss*n)\n",
    "        self.ns.append(n)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we're ready to use our `Learner` for the first time!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 True 2.1275552130636814 0.2314922378287042\n"
     ]
    },
    {
     "data": {
      "text/html": [],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 False 1.9942575636942674 0.2991082802547771\n"
     ]
    }
   ],
   "source": [
    "cbs = [SetupLearnerCB(),TrackResults()]\n",
    "learn = Learner(simple_cnn(), dls, cross_entropy, lr=0.1, cbs=cbs)\n",
    "learn.fit(1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It's quite amazing to realize that we can implement all the key ideas from fastai's `Learner` in so little code! Let's now add some learning rate scheduling."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Scheduling the Learning Rate"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we're going to get good results, we'll want an LR finder and 1cycle training. These are both *annealing* callbacks—that is, they are gradually changing hyperparameters as we train. Here's `LRFinder`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class LRFinder(Callback):\n",
    "    def before_fit(self):\n",
    "        self.losses,self.lrs = [],[]\n",
    "        self.learner.lr = 1e-6\n",
    "        \n",
    "    def before_batch(self):\n",
    "        if not self.model.training: return\n",
    "        self.opt.lr *= 1.2\n",
    "\n",
    "    def after_batch(self):\n",
    "        if not self.model.training: return\n",
    "        if self.opt.lr>10 or torch.isnan(self.loss): raise CancelFitException\n",
    "        self.losses.append(self.loss.item())\n",
    "        self.lrs.append(self.opt.lr)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This shows how we're using `CancelFitException`, which is itself an empty class, only used to signify the type of exception. You can see in `Learner` that this exception is caught. (You should add and test `CancelBatchException`, `CancelEpochException`, etc. yourself.) Let's try it out, by adding it to our list of callbacks:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 True 2.6336045582954903 0.11014890695955222\n"
     ]
    },
    {
     "data": {
      "text/html": [],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 False 2.230653363853503 0.18318471337579617\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "\n",
       "    <div>\n",
       "        <style>\n",
       "            /* Turns off some styling */\n",
       "            progress {\n",
       "                /* gets rid of default border in Firefox and Opera. */\n",
       "                border: none;\n",
       "                /* Needs to be in here for Safari polyfill so background images work as expected. */\n",
       "                background-size: auto;\n",
       "            }\n",
       "            .progress-bar-interrupted, .progress-bar-interrupted::-webkit-progress-bar {\n",
       "                background: #F44336;\n",
       "            }\n",
       "        </style>\n",
       "      <progress value='12' class='' max='74', style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
       "      16.22% [12/74 00:02<00:12]\n",
       "    </div>\n",
       "    "
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "lrfind = LRFinder()\n",
    "learn = Learner(simple_cnn(), dls, cross_entropy, lr=0.1, cbs=cbs+[lrfind])\n",
    "learn.fit(2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And take a look at the results:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.plot(lrfind.lrs[:-2],lrfind.losses[:-2])\n",
    "plt.xscale('log')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can define our `OneCycle` training callback:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class OneCycle(Callback):\n",
    "    def __init__(self, base_lr): self.base_lr = base_lr\n",
    "    def before_fit(self): self.lrs = []\n",
    "\n",
    "    def before_batch(self):\n",
    "        if not self.model.training: return\n",
    "        n = len(self.dls.train)\n",
    "        bn = self.epoch*n + self.num\n",
    "        mn = self.n_epochs*n\n",
    "        pct = bn/mn\n",
    "        pct_start,div_start = 0.25,10\n",
    "        if pct<pct_start:\n",
    "            pct /= pct_start\n",
    "            lr = (1-pct)*self.base_lr/div_start + pct*self.base_lr\n",
    "        else:\n",
    "            pct = (pct-pct_start)/(1-pct_start)\n",
    "            lr = (1-pct)*self.base_lr\n",
    "        self.opt.lr = lr\n",
    "        self.lrs.append(lr)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We'll try an LR of 0.1:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "onecyc = OneCycle(0.1)\n",
    "learn = Learner(simple_cnn(), dls, cross_entropy, lr=0.1, cbs=cbs+[onecyc])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's fit for a while and see how it looks (we won't show all the output in the book—try it in the notebook to see the results):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#hide_output\n",
    "learn.fit(8)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we'll check that the learning rate followed the schedule we defined (as you see, we're not using cosine annealing here):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.plot(onecyc.lrs);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conclusion"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We have explored the key concepts of the fastai library are implemented by re-implementing them in this chapter. Since it's mostly full of code, you should definitely try to experiment with it by looking at the corresponding notebook on the book's website. Now that you know how it's built, as a next step be sure to check out the intermediate and advanced tutorials in the fastai documentation to learn how to customize every bit of the library."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Questionnaire"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> tip: Experiments: For the questions here that ask you to explain what some function or class is, you should also complete your own code experiments."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. What is `glob`?\n",
    "1. How do you open an image with the Python imaging library?\n",
    "1. What does `L.map` do?\n",
    "1. What does `Self` do?\n",
    "1. What is `L.val2idx`?\n",
    "1. What methods do you need to implement to create your own `Dataset`?\n",
    "1. Why do we call `convert` when we open an image from Imagenette?\n",
    "1. What does `~` do? How is it useful for splitting training and validation sets?\n",
    "1. Does `~` work with the `L` or `Tensor` classes? What about NumPy arrays, Python lists, or pandas DataFrames?\n",
    "1. What is `ProcessPoolExecutor`?\n",
    "1. How does `L.range(self.ds)` work?\n",
    "1. What is `__iter__`?\n",
    "1. What is `first`?\n",
    "1. What is `permute`? Why is it needed?\n",
    "1. What is a recursive function? How does it help us define the `parameters` method?\n",
    "1. Write a recursive function that returns the first 20 items of the Fibonacci sequence.\n",
    "1. What is `super`?\n",
    "1. Why do subclasses of `Module` need to override `forward` instead of defining `__call__`?\n",
    "1. In `ConvLayer`, why does `init` depend on `act`?\n",
    "1. Why does `Sequential` need to call `register_modules`?\n",
    "1. Write a hook that prints the shape of every layer's activations.\n",
    "1. What is \"LogSumExp\"?\n",
    "1. Why is `log_softmax` useful?\n",
    "1. What is `GetAttr`? How is it helpful for callbacks?\n",
    "1. Reimplement one of the callbacks in this chapter without inheriting from `Callback` or `GetAttr`.\n",
    "1. What does `Learner.__call__` do?\n",
    "1. What is `getattr`? (Note the case difference to `GetAttr`!)\n",
    "1. Why is there a `try` block in `fit`?\n",
    "1. Why do we check for `model.training` in `one_batch`?\n",
    "1. What is `store_attr`?\n",
    "1. What is the purpose of `TrackResults.before_epoch`?\n",
    "1. What does `model.cuda` do? How does it work?\n",
    "1. Why do we need to check `model.training` in `LRFinder` and `OneCycle`?\n",
    "1. Use cosine annealing in `OneCycle`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Further Research"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. Write `resnet18` from scratch (refer to <<chapter_resnet>> as needed), and train it with the `Learner` in this chapter.\n",
    "1. Implement a batchnorm layer from scratch and use it in your `resnet18`.\n",
    "1. Write a Mixup callback for use in this chapter.\n",
    "1. Add momentum to SGD.\n",
    "1. Pick a few features that you're interested in from fastai (or any other library) and implement them in this chapter.\n",
    "1. Pick a research paper that's not yet implemented in fastai or PyTorch and implement it in this chapter.\n",
    "  - Port it over to fastai.\n",
    "  - Submit a pull request to fastai, or create your own extension module and release it. \n",
    "  - Hint: you may find it helpful to use [`nbdev`](https://nbdev.fast.ai/) to create and deploy your package."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "jupytext": {
   "split_at_heading": true
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
